#-*-coding:utf-8-*-
import datetime

class MZ_Date(object):
    def __init__(self):
        super(MZ_Date,self).__init__()



    def getWeekday(self,int_year,int_month,int_day):
        '''
        获取星期几
        :return:
        '''
        #这是获取当前星期
        # a=time.localtime()
        # # d=time.strftime("%A",a)
        # w=time.strftime("%w",a)


        weekday = datetime.datetime(int_year, int_month, int_day).strftime("%w")
        # print(weekday)
        if weekday=='0':
            return 7
        else:
            return int(weekday)


    def isWeekend(self,date):
        '''
        该函数用来判断给定日期是否为周末.
        :param date: 格式类似 2019-06-05
        :return:
        '''
        datelist=date.split('-')
        year=datelist[0]
        month=datelist[1]
        day=datelist[2]
        int_year=self.str2int(year)
        int_month=self.str2int(month)
        int_day=self.str2int(day)

        weekday=self.getWeekday(int_year,int_month,int_day)
        if weekday==7:
            return True
        else:
            return False


    def isLeapyear(self,year):
        '''
        判定是否为闰年
        :param year:
        :return:
        '''
        if (year % 4) == 0:
            if (year % 100) == 0:
                if (year % 400) == 0:
                    # print("{0} 是闰年".format(year))  # 整百年能被400整除的是闰年
                    return True
                else:
                    # print("{0} 不是闰年".format(year))
                    return  False
            else:
                # print("{0} 是闰年".format(year))  # 非整百年能被4整除的为闰年
                return True
        else:
            # print("{0} 不是闰年".format(year))
            return False




    def isMonth31(self,month):
        '''
        判定该月是否为3月
        :param month:
        :return:
        '''
        have31=['01','03','05','07','08','10','12']
        if month in have31:
            return True
        else:
            return False

    def getMonthDayCount(self,int_year, int_month):
        '''
        该函数获取给定月的所有日期数
        :param int_year:
        :param int_month:
        :return:
        '''
        day31=[1, 3, 5, 7, 8, 10, 12]


        if int_month == 2:
            if self.isLeapyear(int_year):#当是闰年时
                return 29
            else:
                return 28

        elif int_month in day31:
            return 31
        else:
            return 30



    def getPerSunday(self,int_year, int_month):
        '''
        该函数根据提供的年、月来获取该月每个星期日
        :param int_year: 2019
        :param int_month: 6
        :return: 因为不能通用，所以返回一个元组，一个是数值，一个具体日期
        （[2,9,16,23,30],['2019-06-02', '2019-06-09', '2019-06-16', '2019-06-23', '2019-06-30']）

        '''
        daylist=[]
        sundayList = []
        daycount = self.getMonthDayCount(int_year,int_month)
        for i in range(1, daycount + 1):
            weekday = datetime.datetime(int_year, int_month, i).strftime("%w")
            if weekday == '0':
                daylist.append(i)
                date=self.int2str(int_year)+'-'+self.int2str(int_month)+'-'+self.int2str(i)
                sundayList.append(date)

        return (daylist,sundayList)






    def getLastMonthDay(self,year,month):
        month31 = [1, 3, 5, 7, 8, 10, 12]  # 这些月有31天，其实可以把3去掉，但没关系
        if month==3:#主要判断给定月是不是3月即可知道上月是不是2月
            #当是3月时，则要判定是不是闰年
            if self.isLeapyear(year):#当是闰年时
                return 29

            else:
                return 28

        else: #不是三月的话，那么判定该月的上一月是不是31天即可
            if month in month31:#在上月是2月排除的情况下，如果给定月是属于31天组，那么上月就只能是30天
                return 30

            else:
                return 31


    def getLastMonth(self,month):
        '''
        给定month获取上一个月的month
        :param month:
        :return:
        '''
        if month==1:
            return 12
        else:
            return month-1




    def str2int(self,day):
        '''
        将当前日数转成整数,eg: str 05 => int 5
        :param day:
        :return:
        '''
        if day.startswith('0'):
            return int(day[1:])
        else:
            return int(day)


    def int2str(self,day):
        '''
        如果day小于10，则返回加0字符串
        :param day:
        :return:
        '''
        if day<10:
            return '0'+str(day)
        else:
            return str(day)




    def weekOne2Date_list(self,date):
        '''
        日期分析算法:
        1.获取当前的日期
        2.得到今天星期几
        3.得到这周星期一，到给定日期为止的所有日期数（难点在 跨月份）
        :param date: 给定的日期，一般是今天，但是可能那帮2b会手动输入指定截取日期
        :return: 一个列表，包含这周的所有日期，eg:如果输入是2019-06-01则返回 ['2019-05-27','2019-05-28','2019-05-29','2019-05-30','2019-05-31','2019-06-01']
        注：如果要查询上周的信息必须查询上周星期日

        拆分步骤3的算法。如果查询星期为星期日，日期为7，则查询一周为 01-07，星期一到星期日，
        如果查询星期为星期日，日期为06，则查询一周为 上月的28,29，30或者31 到这月的06号，所以判断临界点D是日期是否为06，
        算法如下：
        *****
        假设查询日期为D.星期为W, 年份Y，月份M
        if int(D)>6:
            查询的一周起始日期为D-W+1,注意要日期格式化，当数字小于等于9时，前面加0，dateFormate(D-W+1)
            结果为：[Y-M-dateFormate(int(D)-W+1),..., Y-M-D]
        else:

        if Y为闰年:

            其实都可以通用，既然我们拿到了指定月的数值，我们只需要知道上月是不是2月，如果是2月，那是不是闰年二月即可，
            上月末日期数L+int(D)-W+1 ，eg: 三月 ，星期6 ，日期为02，则 这周第一天为：28+2-6+1=25，



        '''

        # com=re.compile('(.*-)(.*)(-.*)')
        # g = com.match(date)
        #
        # year=g.group(1) #给定年
        # month=g.group(2)#给定月
        # day=g.group(3)#给定日
        splitDate=date.split("-")
        year=splitDate[0]
        month=splitDate[1]
        day=splitDate[2]

    #先拿星期W
        int_year=int(year)
        int_month=self.str2int(month)
        D=self.str2int(day) #拿到日期数-> D
        # print(D)
        W=self.getWeekday(int_year,int_month,D)
        # print(W)

    #拿个上月日期
        last_month = self.getLastMonth(int_month)#这里还是整数

    #获取上月月末日期数L，这里有问题，现在只是考虑跨月情况，还有非跨月情况，所以用SD来表示起始日期，当前指定日期D
    #当起始日期SD>D时，表示跨月了，然后进行下面操作，如果没跨月，那么就是D-W+1,或者直接使用D>6来判定，
        weekday_list = []
        if D>6: #当非跨月时
            SD=D-W+1
            for i in range(SD,D+1):
                date=year+'-'+month+'-'+self.int2str(i)
                weekday_list.append(date)

        else:#当跨月时
            L=self.getLastMonthDay(int_year,int_month)#先获取上月的月末日期

        #然后得到周起始日期
            SD=L+D-W+1

        #然后分开2次循环，一个是上月的循环，一个该月循环，最后加入一起
            for k in range(SD,L+1):
                date=year+'-'+self.int2str(last_month)+'-'+self.int2str(k)
                weekday_list.append(date)

            for g in range(1,D+1):
                date = year + '-' + month + '-' + self.int2str(g)
                weekday_list.append(date)
        #到此获取到了，给定日期，拿到当前日期所在周一到该日期的日期列表

        return weekday_list







#MZ_Date类实现 日期的操作，关键是获取当前周周一到指定日的所有日期analysisDate，以及生成当月每周日期getPerSunday
#analysisDate很灵活，但是适用于实时计算，而且缺点是，如果有人获取非星期天的数量时，会出现计算不完整的情况。
# 所以用于统计的话，最好能定时生成每周的数据，可以每天刷新当周数据，


#方案有2个：
#方法一，直接指定任意日期，然后获取当前日期所在整周的所有日期列表
#方法二，直接指定任意月份，可以选择第几周,因为每月的周数量不靠谱，所以个人觉得用第一种
#而且有给定任意年月，可以获取到每月的周末具体日期，所以可以对接方法一


    def getWeeklist(self,date):
        '''
        该函数是给定日期，获取给定日期所在的一整周的所有日期列表
        :param date: eg: 2019-06-01
        :return:  eg: ['2019-05-27','2019-05-28','2019-05-29','2019-05-30','2019-05-31','2019-06-01','2019-06-02']
        '''
        datelist=date.split('-')
        year=datelist[0]
        month=datelist[1]
        day=datelist[2]
        int_year=self.str2int(year)
        int_month=self.str2int(month)
        int_day=self.str2int(day)

        weekend_list=self.getPerSunday(int_year,int_month)[0]

        date=''

        closestDay=self.getClosestDay(int_day,weekend_list)
        date = year + '-' + month + '-' + self.int2str(closestDay)
        weekont2date=self.weekOne2Date_list(date)
        return weekont2date




    def getClosestDay(self,d,d_list):
        '''
        该函数获取一个数在一个数列中的最近最大值
        :param d:
        :param d_list:[2,9,16,23,30]
        :return:
        '''
        for i in d_list:
            if i>=d:
                return i



    def getMonthAllWeek(self,int_year,int_month):
        '''
        根据给定年月、获取当月所有具体周的所有日期,每周一个列表，返回当月总列表,用来后续计算每月每周数据
        :param int_year: eg:2019
        :param int_month: eg:6
        :return:eg:[['2019-05-27', '2019-05-28', '2019-05-29', '2019-05-30', '2019-05-31', '2019-06-01', '2019-06-02'],
        ['2019-06-03', '2019-06-04', '2019-06-05', '2019-06-06', '2019-06-07', '2019-06-08', '2019-06-09'],
        ['2019-06-10', '2019-06-11', '2019-06-12', '2019-06-13', '2019-06-14', '2019-06-15', '2019-06-16'],
         ['2019-06-17', '2019-06-18', '2019-06-19', '2019-06-20', '2019-06-21', '2019-06-22', '2019-06-23'],
          ['2019-06-24', '2019-06-25', '2019-06-26', '2019-06-27', '2019-06-28', '2019-06-29', '2019-06-30']]

        '''
        perSunday=self.getPerSunday(int_year,int_month)
        sun_date=perSunday[1]
        all_date_list=[]

        for i in sun_date:
            weeklist=self.getWeeklist(i)
            all_date_list.append(weeklist)
        return all_date_list












if __name__ == '__main__':
    today='2019-06-01'
    mzdate=MZ_Date()
    # utilTodayList=mzdate.weekOne2Date_list(today)
    # print(utilTodayList)
    # perSunday=mzdate.getPerSunday(2019, 6)
    # sundays=perSunday[0]
    # month4=perSunday[1]
    # print(sundays)
    # print(month4)
    #
    # isweekend=mzdate.isWeekend(today)
    # print(isweekend)
    #
    # weekone2date=mzdate.getWeeklist(today)
    # print(weekone2date)
    #
    allweek_5=mzdate.getMonthAllWeek(2019,5)
    allweek_6=mzdate.getMonthAllWeek(2019,6)
    allweek_7=mzdate.getMonthAllWeek(2019,7)
    allweek_2=mzdate.getMonthAllWeek(2019,2)
    allweek_3=mzdate.getMonthAllWeek(2019,3)
    print(allweek_5)
    print(allweek_6)
    print(allweek_7)
    print(allweek_2)
    print(allweek_3)